﻿//  Copyright © 2009-2010 by Rhy A. Mednick
//  All rights reserved.
//  http://rhyduino.codeplex.com
//  
//  Redistribution and use in source and binary forms, with or without modification, 
//  are permitted provided that the following conditions are met:
//  
//  * Redistributions of source code must retain the above copyright notice, this list 
//    of conditions and the following disclaimer.
//  
//  * Redistributions in binary form must reproduce the above copyright notice, this 
//    list of conditions and the following disclaimer in the documentation and/or other 
//    materials provided with the distribution.
//  
//  * Neither the name of Rhy A. Mednick nor the names of its contributors may be used 
//    to endorse or promote products derived from this software without specific prior 
//    written permission.
//  
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
//  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
//  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
//  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhyduino.Message;

namespace Rhyduino.Test
{
    [TestClass]
    public class FunctionalTests
    {
        #region Propertie(s)

        ///<summary>
        ///  Gets or sets the test context which provides
        ///  information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #endregion

        #region Public Methods

        //[TestMethod]
        //public void CycleThroughDigitalPins()
        //{
        //    using (var arduino = new Arduino("COM6"))
        //    {
        //        arduino.Connect();
        //        using (var observer = ConstructAndConfigureObserver("COM3"))
        //        {
        //            //observer.DigitalPortReportReceived += WatchForDigitalPinCycle;
        //            for (var i = 2; i <= 7; i++)
        //            {
        //                // configure the pin for output, and set the value high.
        //                arduino.DigitalPins[i] = new DigitalPin(DigitalPinValue.High, PinMode.Output);
        //                // wait up to a second for the observer to register the change
        //                //DateTime start = DateTime.Now;
        //                //bool found = false;
        //                //bool done = false;
        //                //while (!done)
        //                //{
        //                //    if (observer.DigitalPinState.Data == value<<2)
        //                //    {
        //                //        done = found = true;
        //                //    }
        //                //    //else if (start.AddSeconds(10)<=DateTime.Now)
        //                //    //{
        //                //    //    done = true;
        //                //    //}
        //                //}
        //                //Assert.IsTrue(found, "Expected Value: {0}, Actual:{1}", value<<2, observer.DigitalPinState.Data);

        //                Thread.Sleep(100);
        //            }
        //            for (var i = 7; i <= 13; i++)
        //            {
        //                arduino.Post(FirmataEncoder.BuildSetPinModeRequest(i, PinMode.Output));
        //                arduino.Post(FirmataEncoder.BuildDigitalWriteRequest(1, 1 << (i - 7)));
        //                Console.WriteLine("Posted 1:{0:X2}", 1 << (i - 7));
        //                Thread.Sleep(100);
        //            }
        //            Thread.Sleep(5000);
        //            //Task.Factory.
        //        }
        //    }
        //}

        #endregion

        #region Private Methods

        //private static Arduino ConstructAndConfigureObserver(string serialPort)
        //{
        //    // Construct the observer
        //    var observer = new Arduino(serialPort);
        //    // Open the connection so we can begin sending messages
        //    observer.Connect();
        //    // Put everything into input mode
        //    for (var pinNumber = 2; pinNumber < 14; pinNumber++)
        //    {
        //        observer.DigitalPins[pinNumber] = new DigitalPin(DigitalPinValue.None, PinMode.Input);
        //    }
        //    // And start listening
        //    observer.Post(FirmataEncoder.BuildReportDigitalPortRequest(0, true));
        //    observer.Post(FirmataEncoder.BuildReportDigitalPortRequest(1, true));

        //    return observer;
        //}

        private void WatchForDigitalPinCycle(object sender, FirmataEventArgs<DigitalPortReport> message)
        {
            Assert.IsNotNull(message);
            Assert.AreEqual(_expectedPort, message.Data.Port);
            if (message.Data.Value == _ignoreValue)
            {
                return;
            }

            Assert.AreEqual(_expectedValue, message.Data.Value);
            lock (_editLock)
            {
                _ignoreValue = _expectedValue;
                _expectedValue <<= 1;
                if ((_expectedPort != 0) || _expectedValue != (1 << 7))
                {
                    return;
                }
                //switch port
                _expectedPort = 1;
                _expectedValue = 1;
            }
        }

        #endregion

        #region Private Fields

        private readonly object _editLock = new object();
        private int _expectedPort;
        private int _expectedValue = 1 << 2;
        private int _ignoreValue;

        #endregion

        // I need a task like, "Wait for value, with timeout" or something
    }
}